//创建用户相关的小仓库
import { defineStore } from 'pinia'
// 引入登陆接口
import { reqLogin, reqUserInfo, reqLogOut } from '@/api/user'
// 引入数据类型
import type {
  loginFormData,
  loginResponseData,
  userInfoResponseData,
} from '@/api/user/type'
// 引入store数据类型
import type { UseStore } from './types/type'
// 引入本地存储token的方法
import { SET_TOKEN, GET_TOKEN, DEL_TOKEN } from '@/utils/token'
//引入深拷贝方法 lodash里面的深拷贝
//@ts-expect-error 忽略这个文件的ts校验
import cloneDeep from 'lodash/cloneDeep'
import router from '@/router'
// 引入常量路由数组 动态路由数组 和 任意路由 到pinia 方便其他组件使用
import { constantRoute, asyncRoute, anyRoute } from '@/router/routes'
// 过滤动态路由的方法 过滤当前用户要展示的异步路由 我们是以路由的name作为标识
function filterAsyncRoute(asyncRoute: any, routes: any) {
  return asyncRoute.filter((item: any) => {
    // 如果路由数组里面包含的有异步路由的名字 就过滤出来返回新的数组
    if (routes.includes(item.name)) {
      // 会发现只过滤一次 他会将只要包含一级路由 那么他的子路由都会一起被拿到 但是有的用户不是拥有全部的子路由权限 就需要递归过滤 将一级路由的子路由 将用户路由信息进行筛选过滤 进行赋值
      // 如果当前路由 有子路由且子路由的长度大于0 就接着递归进行过滤 二级 三级的路由
      if (item.children && item.children.length > 0) {
        // 过滤完 将过滤到的数量重新给子路由
        item.children = filterAsyncRoute(item.children, routes)
      }
      return true
    }
  })
}

// 创建小仓库方法
const useUserStore = defineStore('User', {
  state: (): UseStore => {
    return {
      // 这里也用本地存储的token
      // token:localStorage.getItem('TOKEN') //用户唯一标识
      token: GET_TOKEN(),
      menuRoutes: constantRoute, //仓库存储 生成路由菜单需要的数组（常量路由）
      username: '', //用户名字
      avatar: '', //用户头像
      buttons: [], //用户包含的按钮权限
    }
  },
  actions: {
    // 用户登录 携带参数发送登录请求
    async userLogin(data: loginFormData) {
      // 获取接口数据
      const res: loginResponseData = await reqLogin(data)
      // console.log(res); //{code: 200, data: {token:'gggg'}} 类似这样的对象
      // 登录成功 200——得到token
      if (res.code == 200) {
        this.token = res.data as string
        // 登录后 可能要去携带token访问其他页面
        // 这里进行持久化处理 保存在本地
        // localStorage.setItem('TOKEN',(res.data.token) as string)
        SET_TOKEN(res.data as string)
        // async函数返回的是promise函数成功或者失败 这里是成功
        return 'ok'
      } else {
        // 登陆失败 201 ——提示登录错误信息
        // 因为返回的是一个promise对象结果
        return Promise.reject(new Error(res.data))
      }
    },
    // 点击登录 获取用户的头像以及名字
    async userinfo() {
      // 必须要有token才能获取到 那就在响应拦截器里携带
      const res: userInfoResponseData = await reqUserInfo()
      // console.log(res);
      // 如果获取成功即code为200  就获取到头像和名字
      if (res.code == 200) {
        this.username = res.data.name
        this.avatar = res.data.avatar
        this.buttons = res.data.buttons
        // --------------------------------------------------------------路由筛选过滤 动态展示
        // 点击登录后获取到用户信息 data里面包含该用户可访问的路由名字的数组 我们将这个路由数组与 动态路由数组进行对比筛选  上面先把这个过滤方法写一下
        // 计算当前用户要展示的异步路由
        const userAsyncRoute = filterAsyncRoute(
          cloneDeep(asyncRoute),
          res.data.routes,
        )
        // // 现在展示路由数组只有常量路由 我们重新赋值 将异步路由和任意路由也加进去
        this.menuRoutes = [...constantRoute, ...userAsyncRoute, anyRoute]
        //目前路由器管理的只有常量路由:用户计算完毕异步路由、任意路由动态追加
        ;[...userAsyncRoute, anyRoute].forEach((route: any) => {
          router.addRoute(route)
        })

        //async 肯定返回一个promise对象 成功的话就是
        return 'ok'
      } else {
        // 失败的话 就是失败的结果
        return Promise.reject(new Error(res.message))
      }
    },
    // 退出登录
    async userOut() {
      const res: any = await reqLogOut()
      // 如果退出成功
      if (res.code == 200) {
        // 1.向服务器发送退出请求（没有mock退出接口 就先不管）
        // 2.清除用户相关的内容 token 用户名和头像
        ;(this.token = ''), (this.avatar = '')
        this.username = ''
        // localStorage.removeItem('TOKEN') //封装了一下
        DEL_TOKEN()
        return 'ok'
      } else {
        return Promise.reject(new Error(res.message))
      }
    },
  },
  getters: {},
})
// 对外暴露方法
export default useUserStore
